﻿#include "IFlowTreeManager.h"
#include <QDomDocument>
#include <QFile>
#include <QJsonObject>
#include <QMetaProperty>

#include "IPluginOperator.h"


using namespace CVV::Interface;
IFlowTreeManager *IFlowTreeManager::instance()
{
    static IFlowTreeManager instance;
    return &instance;
}

void IFlowTreeManager::updateFlowTree(const QString &flowId, const QMap<QString, FlowTree> &hashFlowTree)
{
    if (flowId.isEmpty())
    {
        return;
    }

    if (m_hashFlowTree.contains(flowId))
    {
        m_hashFlowTree[flowId].clear();
    }

    for (auto it = hashFlowTree.begin(); it != hashFlowTree.end(); ++it)
    {
        m_hashFlowTree[flowId].insert(it.key(), it.value());
    }
}

void IFlowTreeManager::initPluginParams(const QString &flowId, const QHash<QString, QJsonArray> &pluginParam)
{
    if (flowId.isEmpty())
    {
        return;
    }

    m_hashPluginParams[flowId] = pluginParam;
}

void IFlowTreeManager::updateDynamicParam(const QString &flowId,
                                          const QString &cellId,
                                          const QString &pluginCode,
                                          const QJsonArray &dynamicParam)
{
    if (flowId.isEmpty() || cellId.isEmpty() || pluginCode.isEmpty())
    {
        return;
    }

    QString strKey = QString("%1_%2").arg(pluginCode).arg(cellId);
    QJsonArray pluginParam = m_hashPluginParams.value(flowId).value(pluginCode);
    for (auto obj : dynamicParam)
    {
        pluginParam.append(obj);
    }

    m_hashPluginParams[flowId].insert(strKey, pluginParam);
}

QList<FlowTree> IFlowTreeManager::getPrevOutFlowTree(const QString &flowId, const QString &cellId)
{
    QList<FlowTree> lstPreFlowTree;
    if (flowId.isEmpty() || cellId.isEmpty())
    {
        return lstPreFlowTree;
    }

    QHash<QString, FlowTree> hashFlowTree = m_hashFlowTree.value(flowId);
    findAllPreOutFlowTree(hashFlowTree.values(), hashFlowTree.value(cellId), lstPreFlowTree);
    lstPreFlowTree.removeAll(hashFlowTree.value(cellId));          //剔除本身

    return lstPreFlowTree;
}

QHash<QString, FlowTree> IFlowTreeManager::getFlowTree(const QString &flowId)
{
    QHash<QString, FlowTree> hashFlowTree;
    if (flowId.isEmpty())
    {
        return hashFlowTree;
    }

    hashFlowTree = m_hashFlowTree.value(flowId);

    return hashFlowTree;
}

QJsonArray IFlowTreeManager::getPluginParam(const QString &flowId, const QString &cellId, const QString &pluginCode)
{
    QJsonArray pluginParam;
    if (flowId.isEmpty() || cellId.isEmpty() || pluginCode.isEmpty())
    {
        return pluginParam;
    }

    QString strKey = QString("%1_%2").arg(pluginCode).arg(cellId);
    if (m_hashPluginParams.value(flowId).contains(strKey))
    {
        pluginParam = m_hashPluginParams.value(flowId).value(strKey);
    }
    else
    {
        pluginParam = m_hashPluginParams.value(flowId).value(pluginCode);
    }

    return pluginParam;
}

void IFlowTreeManager::clearFlowTree(const QString &flowId)
{
    if (flowId.isEmpty())
    {
        return;
    }

    m_hashFlowTree.remove(flowId);
    m_hashPluginParams.remove(flowId);
}

QHash<QString, QList<FlowCellParam>> IFlowTreeManager::getFlowCellParamByFile(const QString &fileName)
{
    QFile docFile(fileName);
    if (!docFile.exists())
    {
        return QHash<QString, QList<FlowCellParam>>();
    }
    QDomDocument doc;
    if (!docFile.open(QIODevice::ReadOnly))
    {
        return QHash<QString, QList<FlowCellParam>>();
    }
    if (!doc.setContent(&docFile))
    {
        docFile.close();
        return QHash<QString, QList<FlowCellParam>>();
    }
    docFile.close();

    QDomElement algorithm = doc.firstChildElement("algorithm");
    QDomElement branch =  algorithm.firstChildElement("branch");
    QDomNodeList children = branch.childNodes();
    QMap<QString, FlowTree> flowTreeMaps;
    int iLevel = 1;
    for(int i = 0; i < children.size(); ++i)
    {
       FlowTree tree;
       QDomElement child = children.at(i).toElement();

       QString cellId = child.attribute("id");
       tree.setCellId(cellId);
       tree.setPluginCode(child.attribute("code"));
       tree.setPluginName(child.attribute("title"));
       tree.setPreCellId(child.attribute("preId"));
       tree.setLevel(iLevel);
       flowTreeMaps.insert(cellId, tree);
       iLevel++;

       if (0 == child.attribute("category").compare("ProcessControl"))
       {
           findChildPlugin(child, iLevel, flowTreeMaps);
       }
    }
    QHash<QString, QList<FlowCellParam>> hashFlowCellParam;
    QList<PluginDesc> lstPluginDesc = CVV::Interface::IPluginOperator::getPluginDescList();
    for (auto ft : flowTreeMaps)
    {
        for (auto desc : lstPluginDesc)
        {
            if (desc.code() == ft.pluginCode())
            {
                QJsonArray jsAry = desc.params();
                QList<FlowCellParam> flowCellParams;
                for( auto param : jsAry)
                {
                    QJsonObject pobj = param.toObject();
                    FlowCellParam fcp;
                    const QMetaObject* metaObj = fcp.metaObject();
                    int propertyCnt = metaObj->propertyCount();
                    for ( int i = 1; i < propertyCnt; ++i )
                    {
                        QMetaProperty oneProperty = metaObj->property(i);
                        QString properyName = oneProperty.name();
                        if(properyName == "Value")
                        {
                        }
                        else
                        {
                            QString val = pobj.value(properyName).toString();
                            fcp.setProperty(oneProperty.name(), val);
                        }
                    }
                    fcp.setPluginCode(ft.pluginCode());
                    fcp.setPluginId(ft.cellId());
                    if (0 == fcp.paramType().compare("Out", Qt::CaseInsensitive))
                    {
                        flowCellParams.append(fcp);
                    }
                }
                hashFlowCellParam.insert(QString("%1_%2").arg(ft.pluginName()).arg(ft.cellId()), flowCellParams);
                break;
            }
        }
    }

    return hashFlowCellParam;
}

IFlowTreeManager::IFlowTreeManager(QObject *parent)
    : QObject(parent)
{
    m_hashFlowTree.clear();
    m_hashPluginParams.clear();
}

IFlowTreeManager::~IFlowTreeManager()
{

}

void IFlowTreeManager::findAllPreOutFlowTree(const QList<FlowTree> &lstAllFlowTree,
                                             const FlowTree &paFlowTree,
                                             QList<FlowTree> &lstPreFlowTree)
{
    QString strPreId = paFlowTree.preCellId();
    if (strPreId == paFlowTree.cellId())
    {
        return;
    }

    QStringList lstPreId = strPreId.split(",");
    for (auto flowTree : qAsConst(lstAllFlowTree))
    {
        if (lstPreId.contains(flowTree.cellId()))     // 上级节点和上级节点的子节点
        {
            if (!lstPreFlowTree.contains(flowTree))
            {
                lstPreFlowTree.append(flowTree);
            }
            findAllPreOutFlowTree(lstAllFlowTree, flowTree, lstPreFlowTree);
        }
    }
}

void IFlowTreeManager::findChildPlugin(const QDomElement &element, int &level, QMap<QString, FlowTree> &mapflowTree)
{
    int iTmpLevel = level;
    QDomNode node = element.firstChild();
    while (!node.isNull()) {
        if (node.isElement())
        {
            int iLevelId = iTmpLevel;
            QDomElement childElement = node.toElement();
            if ("branch" == childElement.tagName())
            {
                QDomNodeList nodeList = childElement.childNodes();
                for (int i = 0; i < nodeList.count(); ++i)
                {
                    QDomElement nodeEle = nodeList.at(i).toElement();

                    FlowTree tree;
                    QString cellId = nodeEle.attribute("id");
                    tree.setCellId(cellId);
                    tree.setPluginCode(nodeEle.attribute("code"));
                    tree.setPluginName(nodeEle.attribute("title"));
                    tree.setPreCellId(nodeEle.attribute("preId"));
                    ++iLevelId;
                    tree.setLevel(iLevelId);
                    mapflowTree.insert(cellId, tree);

                    if (0 == nodeEle.attribute("category").compare("ProcessControl"))
                    {
                        findChildPlugin(nodeEle, iLevelId, mapflowTree);
                    }
                }
                if (level < iLevelId)
                {
                    level = iLevelId;
                }
            }
        }
        node = node.nextSibling();
    }
}
